module Wilsonloops_module


mutable struct Wilson_loop
    wilson_loop::Array{Tuple{Int8,Int8},1}
    origin::NTuple{4,Int8}
    Wilson_loop() = new([], (0, 0, 0, 0))
    #Wilson_loop(loop::Array{Tuple{Int,Int},1},origin) = new(loop,origin)
    #Wilson_loop(loop,origin) = new([Tuple(loop)],origin)
    #Wilson_loop(loop::Array{Tuple{Int,Int},1}) = new(loop,(0,0,0,0))

    function Wilson_loop(loop::Array{Tuple{T,T},1}) where {T<:Integer}
        return new(make_links(loop), (0, 0, 0, 0))
    end
    function Wilson_loop(loop::Array{Tuple{T,T},1}, origin) where {T<:Integer}
        return new(make_links(loop), origin)
    end

    Wilson_loop(loop) = new([Tuple(loop)], (0, 0, 0, 0))
end

mutable struct Tensor_wilson_lines
    left::Wilson_loop
    #Array{Tuple{Int8,Int8},1}
    right::Wilson_loop
    #Array{Tuple{Int8,Int8},1}
    position::NTuple{4,Int8}
    origin::NTuple{4,Int8}
    dUμ::NTuple{2,Int8}
    rightstart::NTuple{4,Int8}
end

function get_leftstartposition(w::Tensor_wilson_lines)
    return w.origin
end

function get_rightstartposition(w::Tensor_wilson_lines)
    return w.rightstart
end

mutable struct Tensor_wilson_lines_set
    loopset::Array{Tensor_wilson_lines,1}
    Tensor_wilson_lines_set() = new([])
end



function Base.getindex(g::Tensor_wilson_lines_set, i)
    return g.loopset[i]
end


function Base.length(x::Tensor_wilson_lines_set)
    return length(x.loopset)
end

function Base.push!(g::Tensor_wilson_lines_set, w::Tensor_wilson_lines)
    push!(g.loopset, w)
    return
end

function Base.display(w::Tensor_wilson_lines)
    println("tensor differenciated by ", w.dUμ)
    println("relative origin = ", w.origin)
    println("position = ", w.position)
    println("startpoint for leftpart: ", w.origin)
    println("startpoint for rightpart: ", w.rightstart)
    print("[")
    for i = 1:length(w.left)
        print(w.left[i], ",")
    end
    print("] ")
    print(" ⊗ ")
    print(" [")
    for i = 1:length(w.right)
        print(w.right[i], ",")
    end
    println("]\t")
end

function Base.display(w::Wilson_loop)
    println("origin = ", w.origin)
    print("[")
    for i = 1:length(w)
        print(w.wilson_loop[i], ",")
    end
    println("]\t")
end



function set_origin!(w::Wilson_loop, origin)
    w.origin = origin
end


mutable struct Wilson_loop_set
    #loopset::Set{Wilson_loop}
    #loopset::Array{Wilson,1}
    loopset::Array{Wilson_loop,1}
    Wilson_loop_set() = new([])
end

mutable struct Tensor_derivative_set
    tensors::Array{Array{Dict{Tuple{Int8,Int8},Tensor_wilson_lines_set},1},1}
    function Tensor_derivative_set(staples::Array{Wilson_loop_set,1})
        tensor_derivative =
            Array{Array{Dict{Tuple{Int8,Int8},Tensor_wilson_lines_set},1},1}(undef, 4)
        for mu = 1:4
            #println("$mu -direction")
            #display(staples[i][mu])
            tensor_derivative[mu] = Array{Dict{Tuple{Int8,Int8},Tensor_wilson_lines_set},1}(
                undef,
                length(staples[mu].loopset),
            )

            for (k, link) in enumerate(staples[mu].loopset)
                tensor_derivative[mu][k] = make_tensor_derivative(link)
                #display(tensor_derivative[i][mu][k])
            end
        end
        return new(tensor_derivative)
    end
end

function Base.getindex(g::Tensor_derivative_set, i)
    return g.tensors[i]
end

function Base.display(w::Wilson_loop_set)
    for i = 1:length(w)
        println("$i-th loops")
        display(w[i])
    end
    println("\t")
end

function Base.length(x::Wilson_loop_set)
    return length(x.loopset)
end

function Base.length(x::Wilson_loop)
    return length(x.wilson_loop)
end

function Base.getindex(g::Wilson_loop_set, i)
    return g.loopset[i]
end

function Base.getindex(g::Wilson_loop, i)
    return g.wilson_loop[i]
end

function Base.push!(g::Wilson_loop, link)
    push!(g.wilson_loop, Tuple(link))
    return
end

function Base.push!(g::Wilson_loop_set, w::Wilson_loop)
    push!(g.loopset, w)
    return
end



function make_cloverloops(μ, ν)
    loops = Wilson_loop_set()
    loop_righttop = Wilson_loop([(μ, 1), (ν, 1), (μ, -1), (ν, -1)])
    loop_lefttop = Wilson_loop([(ν, 1), (μ, -1), (ν, -1), (μ, 1)])
    loop_rightbottom = Wilson_loop([(ν, -1), (μ, 1), (ν, 1), (μ, -1)])
    loop_leftbottom = Wilson_loop([(μ, -1), (ν, -1), (μ, 1), (ν, 1)])
    push!(loops, loop_righttop)
    push!(loops, loop_lefttop)
    push!(loops, loop_rightbottom)
    push!(loops, loop_leftbottom)
    return loops
end

function make_originalactions_fromloops(coupling_loops)
    actions = Array{Wilson_loop_set,1}(undef, length(coupling_loops))
    for (i, loopset) in enumerate(coupling_loops)
        actions[i] = make_originalaction(loopset)
    end
    return actions
end

function make_loopforactions(couplinglist, L)
    loops = Array{Wilson_loop_set,1}(undef, length(couplinglist))
    for (i, name) in enumerate(couplinglist)
        if name == "plaq"
            loops[i] = make_plaq()
        elseif name == "rect"
            loops[i] = make_rect()
        elseif name == "polyt"
            loops[i] = make_polyakov(4, L[4])
        elseif name == "polyx"
            loops[i] = make_polyakov(3, L[3])
        elseif name == "polyy"
            loops[i] = make_polyakov(2, L[2])
        elseif name == "polyz"
            loops[i] = make_polyakov(1, L[1])
        else
            error("$name is not supported!")
        end
    end
    return loops
end

function make_originalaction(loopset::Array{T,1}) where {T<:Any}
    loop_wilson = Wilson_loop_set()
    for loops in loopset
        @assert eltype(loops) == Tuple{<:Int,<:Int} "The loop should be like [(1, 1), (2, 1), (1, -1), (2, -1)]"
        loop1 = Wilson_loop(loops)
        push!(loop_wilson, loop1)
    end
    return loop_wilson
end

function make_plaqloops()
    loopset = []
    for μ = 1:4
        for ν = μ:4
            #for ν=1:4
            if ν == μ
                continue
            end
            push!(loopset, [(μ, 1), (ν, 1), (μ, -1), (ν, -1)])
        end
    end
    return loopset
end

function make_rectloops(N)
    loopset = []
    for μ = 1:4
        for ν = μ:4
            if ν == μ
                continue
            end
            push!(loopset, [(μ, 1), (ν, N), (μ, -1), (ν, -N)])
            push!(loopset, [(μ, N), (ν, 1), (μ, -N), (ν, -1)])
        end
    end
    return loopset
end

function make_polyakovloops(μ, Nμ)
    loopset = []
    push!(loopset, [(μ, Nμ)])
    return loopset
end



function make_plaq()
    loopset = make_plaqloops()
    loops = make_originalaction(loopset)
    return loops
end

function make_plaq(origin)
    loops = Wilson_loop_set()
    for μ = 1:4
        #for ν=1:4
        for ν = μ:4
            if ν == μ
                continue
            end
            loop = make_links([(μ, 1), (ν, 1), (μ, -1), (ν, -1)])
            loop1 = Wilson_loop(loop, Tuple(origin))
            push!(loops, loop1)
        end
    end

    return loops
end

function make_plaq(μ, ν)
    loops = Wilson_loop_set()
    origin = zeros(Int8, 4)

    loop = make_links([(μ, 1), (ν, 1), (μ, -1), (ν, -1)])
    loop1 = Wilson_loop(loop, Tuple(origin))
    push!(loops, loop1)


    return loops
end



function make_plaq(μ, ν, origin)
    loops = Wilson_loop_set()
    #origin = zeros(Int8,4)

    loop = make_links([(μ, 1), (ν, 1), (μ, -1), (ν, -1)])
    loop1 = Wilson_loop(loop, Tuple(origin))
    push!(loops, loop1)


    return loops
end

function make_rect()
    loops = Wilson_loop_set()
    origin = zeros(Int8, 4)



    for μ = 1:4
        for ν = μ:4
            if ν == μ
                continue
            end
            #loop = make_links([(μ,1),(ν,2),(μ,-1),(ν,-2)])


            loop1 = Wilson_loop([(μ, 1), (ν, 2), (μ, -1), (ν, -2)])
            #loop1 = Wilson_loop(loop,Tuple(origin))
            push!(loops, loop1)

            loop1 = Wilson_loop([(μ, 2), (ν, 1), (μ, -2), (ν, -1)])
            push!(loops, loop1)
        end
    end

    return loops
end

function make_polyakov(μ, Nμ)
    loops = Wilson_loop_set()
    origin = zeros(Int8, 4)
    loop = make_links([(μ, Nμ)])
    loop1 = Wilson_loop(loop, Tuple(origin))
    push!(loops, loop1)
    return loops
end

function make_polyakov_xyz(Nμ)
    loops = Wilson_loop_set()
    for μ = 1:3
        origin = zeros(Int8, 4)
        loop = make_links([(μ, Nμ)])
        loop1 = Wilson_loop(loop, Tuple(origin))
        push!(loops, loop1)
    end

    return loops
end

function make_chair()
    #loopset = []
    loopset = Wilson_loop_set()
    set1 = (1, 2, 3)
    set2 = (1, 2, 4)
    set3 = (2, 3, 4)
    set4 = (1, 3, 4)

    for set in (set1, set2, set3, set4)
        mu, nu, rho = set
        origin = zeros(Int8, 4)
        loop = [(mu, 1), (nu, 1), (rho, 1), (mu, -1), (rho, -1), (nu, -1)]
        loop1 = Wilson_loop(loop, Tuple(origin))
        push!(loopset, loop1)

        mu, rho, nu = set
        loop = [(mu, 1), (nu, 1), (rho, 1), (mu, -1), (rho, -1), (nu, -1)]
        loop1 = Wilson_loop(loop, Tuple(origin))
        push!(loopset, loop1)

        nu, rho, mu = set
        loop = [(mu, 1), (nu, 1), (rho, 1), (mu, -1), (rho, -1), (nu, -1)]
        loop1 = Wilson_loop(loop, Tuple(origin))
        push!(loopset, loop1)

        nu, mu, rho = set
        loop = [(mu, 1), (nu, 1), (rho, 1), (mu, -1), (rho, -1), (nu, -1)]
        loop1 = Wilson_loop(loop, Tuple(origin))
        push!(loopset, loop1)

        rho, mu, nu = set
        loop = [(mu, 1), (nu, 1), (rho, 1), (mu, -1), (rho, -1), (nu, -1)]
        loop1 = Wilson_loop(loop, Tuple(origin))
        push!(loopset, loop1)

        rho, nu, mu = set
        loop = [(mu, 1), (nu, 1), (rho, 1), (mu, -1), (rho, -1), (nu, -1)]
        loop1 = Wilson_loop(loop, Tuple(origin))
        push!(loopset, loop1)

    end
    return loopset
end

function make_plaq_staple(μ)
    loops = Wilson_loop_set()
    origin = zeros(Int8, 4)
    origin[μ] = 1
    for ν = 1:4
        if ν == μ
            continue
        end
        loop = make_links([(ν, 1), (μ, -1), (ν, -1)])
        loop1 = Wilson_loop(loop, Tuple(origin))
        push!(loops, loop1)

        loop = make_links([(ν, -1), (μ, -1), (ν, 1)])
        loop2 = Wilson_loop(loop, Tuple(origin))
        push!(loops, loop2)
    end
    return loops
end

function Base.adjoint(x::Wilson_loop_set)
    xout = Wilson_loop_set()
    num = length(x)

    for i = 1:num
        xi = x[i]
        #display(xi)
        numloops = length(xi)
        coordinates = calc_coordinate(xi)

        #println("endpoint")
        endpoint = collect(coordinates[end])
        lastlink = xi[numloops]
        #println(lastlink)
        endpoint[lastlink[1]] += lastlink[2]
        #println(endpoint)

        loop = Tuple{Int64,Int64}[]
        for k = numloops:-1:1
            link = xi[k]
            push!(loop, (link[1], -link[2]))
        end
        #println(loop)
        loopw = make_links(loop)

        loop2 = Wilson_loop(loopw, Tuple(endpoint))

        #println(xi)
        #println("inv")
        #display(loop2)
        push!(xout, loop2)
    end
    #exit()
    return xout
end

function make_plaq_staple_prime(μ)
    loops = Wilson_loop_set()
    origin = zeros(Int8, 4)
    #origin[μ] = 1
    for ν = 1:4
        if ν == μ
            continue
        end
        loop = make_links([(ν, 1), (μ, 1), (ν, -1)])
        loop1 = Wilson_loop(loop, Tuple(origin))
        push!(loops, loop1)

        loop2 = Wilson_loop([(ν, -1), (μ, 1), (ν, 1)], Tuple(origin))
        push!(loops, loop2)
    end
    return loops
end

function make_plaq_staple_prime(μ, Dim)
    loops = Wilson_loop_set()
    origin = zeros(Int8, 4)
    #origin[μ] = 1
    for ν = 1:Dim
        if ν == μ
            continue
        end
        loop = make_links([(ν, 1), (μ, 1), (ν, -1)])
        loop1 = Wilson_loop(loop, Tuple(origin))
        push!(loops, loop1)

        loop2 = Wilson_loop([(ν, -1), (μ, 1), (ν, 1)], Tuple(origin))
        push!(loops, loop2)
    end
    return loops
end


function calc_coordinate(w::Wilson_loop)
    numloops = length(w)
    coordinates = Array{NTuple{4,Int8},1}(undef, numloops)

    for k = 1:numloops-1
        if k == 1
            coordinates[k] = w.origin
        end
        loopk = w[k]
        if loopk[1] == 1
            coordinates[k+1] = (
                coordinates[k][1] + loopk[2],
                coordinates[k][2],
                coordinates[k][3],
                coordinates[k][4],
            )
        elseif loopk[1] == 2
            coordinates[k+1] = (
                coordinates[k][1],
                coordinates[k][2] + loopk[2],
                coordinates[k][3],
                coordinates[k][4],
            )
        elseif loopk[1] == 3
            coordinates[k+1] = (
                coordinates[k][1],
                coordinates[k][2],
                coordinates[k][3] + loopk[2],
                coordinates[k][4],
            )
        elseif loopk[1] == 4
            coordinates[k+1] = (
                coordinates[k][1],
                coordinates[k][2],
                coordinates[k][3],
                coordinates[k][4] + loopk[2],
            )
        end
    end
    return coordinates
end


function calc_shift(w::Wilson_loop)
    numloops = length(w)
    coordinates = calc_coordinate(w)
    shifts = Array{NTuple{4,Int8},1}(undef, numloops)
    for k = 1:numloops
        loopk = w[k]
        if loopk[2] == 1
            shifts[k] = coordinates[k]
        elseif loopk[2] == -1
            if loopk[1] == 1
                shifts[k] = (
                    coordinates[k][1] + loopk[2],
                    coordinates[k][2],
                    coordinates[k][3],
                    coordinates[k][4],
                )
            elseif loopk[1] == 2
                shifts[k] = (
                    coordinates[k][1],
                    coordinates[k][2] + loopk[2],
                    coordinates[k][3],
                    coordinates[k][4],
                )
            elseif loopk[1] == 3
                shifts[k] = (
                    coordinates[k][1],
                    coordinates[k][2],
                    coordinates[k][3] + loopk[2],
                    coordinates[k][4],
                )
            elseif loopk[1] == 4
                shifts[k] = (
                    coordinates[k][1],
                    coordinates[k][2],
                    coordinates[k][3],
                    coordinates[k][4] + loopk[2],
                )
            end
        end
    end
    return shifts
end

const kindsof_loops = [
    "plaquette",
    "rectangular",
    "chair",
    "polyakov_x",
    "polyakov_y",
    "polyakov_z",
    "polyakov_t",
]

function make_loops(loops_list, L)
    loops = []
    for loopname in loops_list
        if loopname == "plaquette"
            loop = make_plaq()
        elseif loopname == "rectangular"
            loop = make_rect()
        elseif loopname == "chair"
            loop = make_chair()
        elseif loopname == "polyakov_x"
            loop = make_polyakov(1, L[1])
        elseif loopname == "polyakov_y"
            loop = make_polyakov(2, L[2])
        elseif loopname == "polyakov_z"
            loop = make_polyakov(3, L[3])
        elseif loopname == "polyakov_t"
            loop = make_polyakov(4, L[4])
        else
            error("loop name $(loopname) is not supported!")
        end
        push!(loops, loop)
    end
    return loops
end


function make_links(segments::Array{Tuple{T,T},1}) where {T<:Integer}
    links = Tuple{Int8,Int8}[]
    for segment in segments
        s = sign(segment[2])
        if segment[2] == 0
            push!(links, (segment[1], 0))
        else
            #@assert segment[2] != 0
            for i = 1:abs(segment[2])
                push!(links, (segment[1], s * 1))
            end
        end
    end
    return links
end

function make_staples(w::Wilson_loop_set)
    num = length(w)
    staplesset = Array{Wilson_loop_set,1}(undef, 4)
    tempset = Array{Array{Any,1},1}(undef, 4)
    #tempset = Array{Set,1}(undef,4)
    for mu = 1:4
        staplesset[mu] = Wilson_loop_set()
        #tempset[mu] = Set()
        tempset[mu] = []
    end


    for i = 1:num
        staples = make_staples(w[i])
        for mu = 1:4
            origin = zeros(Int8, 4)
            origin[mu] = 1


            for k = 1:length(staples[mu])
                push!(tempset[mu], staples[mu][k])
                #Wilson_loop(staples[mu][k],Tuple(origin)))
            end




            #for k=1:length(staples[mu])
            #    push!(staplesset[mu],Wilson_loop(staples[mu][k],Tuple(origin))  )
            #end
        end
    end

    for mu = 1:4
        #display(tempset[mu])
        #exit()
        origin = zeros(Int8, 4)
        origin[mu] = 1
        for temp in tempset[mu]
            push!(staplesset[mu], Wilson_loop(temp, Tuple(origin)))
        end
    end

    return staplesset
end

function get_coordinate(w::Wilson_loop, position)
    coor = collect(w.origin)
    if position != 1
        for i = 1:position-1
            link = w.wilson_loop[i]
            coor[link[1]] += link[2]
        end
    end

    return coor
end

#=
mutable struct Tensor_wilson_lines
    left::Array{Tuple{Int8,Int8},1}
    right::Array{Tuple{Int8,Int8},1}
    position::NTuple{4,Int8}
end
=#

function make_tensor_derivative(w::Wilson_loop)
    dVdU = Dict{Tuple{Int8,Int8},Tensor_wilson_lines_set}()
    #display(w)
    for μ = 1:4
        for sign in [+1, -1]
            u = (μ, sign)
            #println("u = $u")
            dVdU[u] = make_tensor_Wilson_line(w, u)
        end
    end
    return dVdU
end

function make_tensor_Wilson_line(w::Wilson_loop, u::Tuple{T,T}) where {T<:Int}
    left = Tuple{Int8,Int8}[]
    right = Tuple{Int8,Int8}[]
    count, positions = count_terms(w, u)
    len = length(w)

    tw = Tensor_wilson_lines_set()
    #println("u = $u count = ",count," position = $positions")
    if count != 0
        #println("u = $u")
        for i = 1:count
            left = Tuple{Int8,Int8}[]
            right = Tuple{Int8,Int8}[]


            position = positions[i]
            coor = get_coordinate(w, position)
            #println("position ", coor)
            #insertpoint = Tuple(collect(w.origin) .- coor)
            insertpoint = Tuple(-collect(coor))
            #println("position2 ", insertpoint )

            #println(positions[i])
            if position == 1
                #println(u)
                push!(left, (0, 0))
                #display(w)
            else
                for k = 1:position-1
                    push!(left, w.wilson_loop[k])
                end
            end
            #println("left = ",left)

            if position == len
                #if u == (1,1)
                #    println(right)
                #end
                push!(right, (0, 0))
            else
                for k = position+1:len
                    push!(right, w.wilson_loop[k])
                end
            end
            #println("right = ",right)
            relativeorigin = [0, 0, 0, 0]
            if left[1] == (0, 0)
            else
                for i = length(left):-1:1
                    link = left[i]
                    relativeorigin[link[1]] -= link[2]
                end
            end

            temp_right = [0, 0, 0, 0]
            temp_right[u[1]] += u[2]

            left_wilson = Wilson_loop(make_links(left), Tuple(relativeorigin))
            right_wilson = Wilson_loop(make_links(right), Tuple(temp_right))

            #tensorlink = Tensor_wilson_lines(left,right,insertpoint,Tuple(relativeorigin),u,Tuple(temp_right))
            tensorlink = Tensor_wilson_lines(
                left_wilson,
                right_wilson,
                insertpoint,
                Tuple(relativeorigin),
                u,
                Tuple(temp_right),
            )

            #=
            if position == len
                if u == (1,1)
                    display(tensorlink)
                end
            end
            =#

            #display(tensorlink)
            push!(tw, tensorlink)
        end


    end
    return tw
end

function count_terms(w::Wilson_loop, u)
    count = 0
    positions = []
    #origin = w.origin
    #x = collect(origin)
    for (i, link) in enumerate(w.wilson_loop)

        if link == u
            count += 1
            push!(positions, i)
        end
        #x[link[1]] += link[2]
        #println(x)
        #println("$link,$count,$positions")
    end
    return count, positions
end

function make_staple_staple(staples::Array{Wilson_loop,1})
    staplestaple = Array{Wilson_loop,2}(undef, 4, 4)
    for ν = 1:4
        staple = make_staples(staples[ν])
        for μ = 1:4
            staplestaple[ν, μ] = staple[μ]
        end
    end
    return staplestaple
end

function make_staples(w::Wilson_loop)
    staples = make_staples(w.wilson_loop)
    return staples[1], staples[2], staples[3], staples[4]
end

function make_staples(links)
    numlinks = length(links)
    #println("num. of links: $numlinks")
    staples = Array{Array{Array{Tuple{Int,Int},1}}}(undef, 4)
    for mu = 1:4
        linkmu = []
        for (i, link) in enumerate(links)
            if link[1] == mu
                append!(linkmu, i)
            end
        end
        #println(mu,"\t",linkmu)

        staple_mu = []

        if length(linkmu) == 0
            staple = Tuple{Int,Int}[]
            staple_mu = Array{Tuple{Int,Int},1}[]
        end

        staple_mu = Array{Array{Tuple{Int,Int},1}}(undef, length(linkmu))
        count = 0
        for i in linkmu
            count += 1
            staple = Array{Tuple{Int,Int}}(undef, numlinks - 1)
            if i != numlinks
                staple[1:numlinks-i] = links[i+1:end]
            end

            if i != 1
                staple[numlinks-i+1:end] = links[1:i-1]
            end

            if links[i][2] == -1
                staple = staple[end:-1:1]
                for j = 1:numlinks-1
                    staple[j] = (staple[j][1], -staple[j][2])
                end
            end
            #println(staple)
            staple_mu[count] = staple[:]
        end
        staples[mu] = staple_mu
        #println(staple_mu)
    end

    #println(staples)
    return staples
end



function calc_loopset_μν_name(name)
    loops_μν = Array{Wilson_loop_set,2}(undef, 4, 4)
    if name == "plaq"
        numofloops = 1
        for μ = 1:4
            for ν = 1:4
                if ν == μ
                    continue
                end
                loops = Wilson_loop_set()
                loop = Wilson_loop([(μ, 1), (ν, 1), (μ, -1), (ν, -1)])
                push!(loops, loop)
                loops_μν[μ, ν] = loops
            end
        end
    elseif name == "clover"
        numofloops = 4
        for μ = 1:4
            for ν = 1:4
                if ν == μ
                    continue
                end
                loops = Wilson_loop_set()

                loop_righttop = Wilson_loop([(μ, 1), (ν, 1), (μ, -1), (ν, -1)])
                loop_lefttop = Wilson_loop([(ν, 1), (μ, -1), (ν, -1), (μ, 1)])
                loop_rightbottom = Wilson_loop([(ν, -1), (μ, 1), (ν, 1), (μ, -1)])
                loop_leftbottom = Wilson_loop([(μ, -1), (ν, -1), (μ, 1), (ν, 1)])
                push!(loops, loop_righttop)
                push!(loops, loop_lefttop)
                push!(loops, loop_rightbottom)
                push!(loops, loop_leftbottom)

                loops_μν[μ, ν] = loops
            end
        end
    elseif name == "rect"
        numofloops = 8
        for μ = 1:4
            for ν = 1:4
                if ν == μ
                    continue
                end
                loops = Wilson_loop_set()

                loop_righttop = Wilson_loop([(μ, 2), (ν, 1), (μ, -2), (ν, -1)])
                loop_lefttop = Wilson_loop([(ν, 1), (μ, -2), (ν, -1), (μ, 2)])
                loop_rightbottom = Wilson_loop([(ν, -1), (μ, 2), (ν, 1), (μ, -2)])
                loop_leftbottom = Wilson_loop([(μ, -2), (ν, -1), (μ, 2), (ν, 1)])
                push!(loops, loop_righttop)
                push!(loops, loop_lefttop)
                push!(loops, loop_rightbottom)
                push!(loops, loop_leftbottom)

                loop_righttop = Wilson_loop([(μ, 1), (ν, 2), (μ, -1), (ν, -2)])
                loop_lefttop = Wilson_loop([(ν, 2), (μ, -1), (ν, -2), (μ, 1)])
                loop_rightbottom = Wilson_loop([(ν, -2), (μ, 1), (ν, 2), (μ, -1)])
                loop_leftbottom = Wilson_loop([(μ, -1), (ν, -2), (μ, 1), (ν, 2)])
                push!(loops, loop_righttop)
                push!(loops, loop_lefttop)
                push!(loops, loop_rightbottom)
                push!(loops, loop_leftbottom)

                loops_μν[μ, ν] = loops
            end
        end
    else
        error("$name is not supported")
    end
    return loops_μν, numofloops
end



end
